This is the pupil preprocessing file when you have data from both eyes.
The same basic workflow is used here, as was detailed in the preprocess.Rmd file, which focussed on preprocessing data for one eye. Therefore, I will not repeat any details here. For a description of the basic workflow and functions, see the preprocess.Rmd file. Here, I’ll just show you the steps that you might take to preprocess and combine pupil data for both eyes.
pkg <- c("pupillometry", "tidyverse", "here", "patchwork", "future", "RColorBrewer",
"parallel")
lapply(pkg, library, character.only = TRUE)
source(here("custom_functions", "preprocess_both.r"))
source(here("custom_functions", "parameter_tests_both.r"))
source(here("custom_functions", "settings.r"))
plan(multicore)
message(paste("Supporting multicore:", supportsMulticore()))
## Supporting multicore: TRUE
message(paste("Available cores:", detectCores()))
## Available cores: 8
simulated pupil data for both eyes across 3 trials and 3 participants
Some extra arguments are required when you have data for both eyes, as you have to specify pupil size plus x and y coordinates for the left and right eye separately.
And if you leave eye_use as the default (NULL), then it will expect data for both eyes to be present.
raw_data_cols <- read_csv("data/sim/sim_pupil_data_both.csv",
n_max = 0) %>%
colnames()
# Find columns to include
already_specified <- c("time", "pupil", "subject", "trial")
cols_to_include <- setdiff(raw_data_cols, already_specified)
## read in
sim_pupil_data_both <- pupil_read(
file = here("data", "sim", "sim_pupil_data_both.csv"),
eyetracker = "",
eye_use = NULL, ## NULL is the default and it keeps both eyes
time = "time",
left_pupil.mm = "pupil_left",
right_pupil.mm = "pupil_right",
left_gaze.x = "x_pos_left",
left_gaze.y = "y_pos_left",
right_gaze.x = "x_pos_right",
right_gaze.y = "y_pos_right",
subject = "subject",
trial = "trial",
delim = ",",
message_event = "message", ## event info stored in this column
include_col = cols_to_include
)
head(sim_pupil_data_both)
## # A tibble: 6 × 11
## Subject Trial Time Stimulus L_Pupil_Diameter.mm R_Pupil_Diameter.mm
## <dbl> <dbl> <dbl> <chr> <dbl> <dbl>
## 1 1 1 0 fixation 2.94 2.94
## 2 1 1 17 fixation 3.03 3.03
## 3 1 1 33 fixation 3.26 3.27
## 4 1 1 50 fixation 3.16 3.21
## 5 1 1 67 fixation 3.22 3.22
## 6 1 1 83 fixation 3.43 3.45
## # ℹ 5 more variables: L_Gaze_Position.x <dbl>, L_Gaze_Position.y <dbl>,
## # R_Gaze_Position.x <dbl>, R_Gaze_Position.y <dbl>, Pupils.r <dbl>
This gives a warning about parsing issues, but the column types seem correct to me. So I think this can be safely ignored. I leave the warning in just for folks who might use other datasets where it could be helpful.
I created a new function to apply preprocessing to both eyes and then combine them at some point. preprocess_and_visualize_both()
custom_params <- list(
deblink = list(extend = 75),
artifact = list(n = 8),
missing = list(missing_allowed = .90),
upsample = list(),
smooth = list(type = "hann", n = 50),
interpolate = list(type = "cubic-spline", maxgap = 1000, hz = 1000),
baseline = list(bc_onset_message = "target", baseline_duration = 1000,
type = "subtractive")
)
results_both <- preprocess_and_visualize_both(
pupil_data = sim_pupil_data_both,
plot_dir = here("figures", "preprocessing", "both_eyes", "sim"),
output_dir = here("data", "preprocessing", "both_eyes", "sim"),
params = custom_params,
save_intermediate_data = FALSE,
save_individual_plots = FALSE,
return_all_steps = TRUE,
bin_length = 200,
smooth_then_interp = TRUE,
units = "mm"
)
By default, the preprocessing script produces a bunch of figures and data, as follows:
In the plot directory, it produces:
An example of subject 1, trial 3 is shown below.
example preprocessing summary plot for both eyes and 1 trial
In the data directory, it produces:
smooth_combinations <- list(
list(type = "mwa", n = 10),
list(type = "mwa", n = 50),
list(type = "mwa", n = 100),
list(type = "mwa", n = 200)
)
smooth_results_both <- test_parameter_combinations_both(
step_data = results_both, # From your preprocessing
param_combinations = smooth_combinations,
processing_function = "pupil_smooth",
input_step = "upsample_data", # Step to use as input
plot_dir = here("figures", "parameter_tests", "both_eyes", "sim", "smooth"),
output_dir = here("data", "parameter_tests", "both_eyes", "sim", "smooth"),
save_param_data = FALSE
)
An example of subject 1, trial 3 is shown below.
example parameter tests plot for both eyes and 1 trial
read in data and create pretend left and right data (i.e., duplicate the existing data just to test that the preprocessing pipeline works with two eyes and arbitrary units).
gazer_data <- read_csv("data/gazer/gazer_data.csv")
# head(gazer_data)
duplicate
gazer_data_both <- gazer_data %>%
rename(pupil_left = pupil, x_pos_left = x, y_pos_left = y) %>%
mutate(pupil_right = pupil_left + 20, x_pos_right = x_pos_left + 20, y_pos_right = y_pos_left)
head(gazer_data_both)
## # A tibble: 6 × 17
## subject trial time pupil_left x_pos_left y_pos_left blink message acc block
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <dbl>
## 1 11 1 0 3635 972. 563. 0 MODERE… 1 0
## 2 11 1 4 3634 973. 565. 0 <NA> 1 0
## 3 11 1 8 3626 972. 567. 0 <NA> 1 0
## 4 11 1 12 3622 971 566. 0 <NA> 1 0
## 5 11 1 16 3621 972. 566. 0 <NA> 1 0
## 6 11 1 20 3621 972. 566. 0 <NA> 1 0
## # ℹ 7 more variables: rt <dbl>, item <chr>, script <chr>, alt <chr>,
## # pupil_right <dbl>, x_pos_right <dbl>, y_pos_right <dbl>
write_csv(gazer_data_both, "data/gazer/gazer_data_both.csv")
gazer_data_cols <- read_csv("data/gazer/gazer_data_both.csv",
n_max = 0) %>%
colnames()
# Find columns to include
already_specified <- c("time", "pupil", "subject", "trial")
cols_to_include <- setdiff(raw_data_cols, already_specified)
## read in
gazer_pupil_data_both <- pupil_read(
file = here("data", "gazer", "gazer_data_both.csv"),
eyetracker = "",
eye_use = NULL, ## NULL is the default and it keeps both eyes
time = "time",
left_pupil.px = "pupil_left",
right_pupil.px = "pupil_right",
left_gaze.x = "x_pos_left",
left_gaze.y = "y_pos_left",
right_gaze.x = "x_pos_right",
right_gaze.y = "y_pos_right",
subject = "subject",
trial = "trial",
delim = ",",
message_event = "message", ## event info stored in this column
include_col = cols_to_include
)
head(gazer_pupil_data_both)
## # A tibble: 6 × 11
## Subject Trial Time Stimulus L_Pupil_Diameter.px R_Pupil_Diameter.px
## <dbl> <dbl> <dbl> <chr> <dbl> <dbl>
## 1 11 1 0 MODERECORDCRL 3635 3655
## 2 11 1 4 MODERECORDCRL 3634 3654
## 3 11 1 8 MODERECORDCRL 3626 3646
## 4 11 1 12 MODERECORDCRL 3622 3642
## 5 11 1 16 MODERECORDCRL 3621 3641
## 6 11 1 20 MODERECORDCRL 3621 3641
## # ℹ 5 more variables: L_Gaze_Position.x <dbl>, L_Gaze_Position.y <dbl>,
## # R_Gaze_Position.x <dbl>, R_Gaze_Position.y <dbl>, Pupils.r <dbl>
custom_params <- list(
deblink = list(extend = 75),
artifact = list(n = 8),
missing = list(missing_allowed = .90),
upsample = list(),
smooth = list(type = "hann", n = 50),
interpolate = list(type = "cubic-spline", maxgap = 500, hz = 1000),
baseline = list(bc_onset_message = "target", baseline_duration = 100,
type = "subtractive")
)
results_both_au <- preprocess_and_visualize_both(
pupil_data = gazer_pupil_data_both,
plot_dir = here("figures", "preprocessing", "both_eyes", "real"),
output_dir = here("data", "preprocessing", "both_eyes", "real"),
params = custom_params,
save_intermediate_data = FALSE,
save_individual_plots = FALSE,
return_all_steps = TRUE,
bin_length = 200,
smooth_then_interp = TRUE,
units = "px"
)
example preprocessing summary plot for both eyes and 1 trial with arbitrary units